package edu.sjsu.cs.queryopt.dbms.main;

import java.util.ArrayList;
import java.util.Hashtable;

public class InnerOrOuterTable {
	static WordCapsule  wc = new WordCapsule();
	static SelectHelper sh = new SelectHelper();
	static CreateTable ct = new CreateTable();
	static Helper hp = new Helper();
	 static FilterFactor ff = new FilterFactor();
	 static InList in = new InList();
	 static AccessTypeOne ato = new AccessTypeOne();
	 static CalCard cc = new CalCard();
	 
	 public void InnerOrOuter(ArrayList<String> output ,
				ArrayList<String> conditionpod ,
				ArrayList<String> frontColpod ,
					ArrayList<String> tablepod ){
//		 System.out.println(" DBMS " + DBMS.PlanTable);
//		 System.out.println(" cc " + cc.prediTable);

		 
		 /**
		  * Rarrange seq when we have join and local predicate
		  * 
		  * */
				if(ato.IsJoinPredicate(conditionpod) && DoYouHaveLocalPredicate(conditionpod)){
//					System.out.println("THIS IS SINGLE WHERE JOIN and local");

					/***
					 * case like SELECT T1.1 FROM T1 , T2 WHERE T1.5 = T2.4
					 * if there is join predicate and local predicate than
					 * we need to find seql 
					 */
//					if(DBMS.PlanTable.get(1).equals("R")){
						/**
						 * HASH JOIN PRE AND LOCAL PRE
						 * BUT DON'T USE INDEX
						 * APPLY FF VALUE TO DO IT
						 * FF * TABLE SIZE
						 * */
//						System.out.println("CCCC PLAN TABLE " + DBMS.PlanTable);
//						System.out.println("CCCC predi TABLE " + cc.prediTable);
						
						String first = "";
						String second = "";
						int remember = 0;
						double firstff = 0.0;
						double secondff = 0.0;
						for(int i = 0 ; i < cc.prediTable.size() ; i++){
							
							if(ato.isJoinPredicateForString(cc.prediTable.get(i).get(6))){
								first = cc.prediTable.get(i).get(3);
								second = cc.prediTable.get(i).get(4);
								remember = i;
								break;
							}
							
						}
						
//						System.out.println("first " + Double.parseDouble(first));
//						System.out.println("second " +  Double.parseDouble(second));
						firstff =  Double.parseDouble(first);
						secondff =  Double.parseDouble(second);
						double firstable = 0.0;
						double secondtable = 0.0;
						if(DBMS.orderby == true ||DBMS.PlanTable.get(6).equals("N") ||DBMS.PlanTable.get(6).equals("Y") ){
						 firstable = Double.parseDouble(DBMS.PlanTable.get(7));
						 secondtable = Double.parseDouble(DBMS.PlanTable.get(8));
						}
						else{
							firstable = Double.parseDouble(DBMS.PlanTable.get(6));
							 secondtable = Double.parseDouble(DBMS.PlanTable.get(7));
						}
						
						double resultfirst =firstff*firstable;
						double resultsecond = secondff*secondtable;
						/**
						 * lager is outer
						 * */
						if(resultfirst > resultsecond){
							DBMS.PlanTable.add(ato.GetLeftOrRight(cc.prediTable.get(remember).get(6), 1));
						}
						else if(resultfirst < resultsecond){
							DBMS.PlanTable.add(ato.GetLeftOrRight(cc.prediTable.get(remember).get(6), 2));
						}
						else{
							DBMS.PlanTable.add(ato.GetLeftOrRight(cc.prediTable.get(remember).get(6), 1));
//						}
					}
						DBMS.PlanTable.set(5, "S");
//					else{
//						/**
//						 * has index and local predicate and jojn
//						 * 
//						 * */
//						
//					}
					rearrangeSeq();
					
				}
				else if(ato.IsJoinPredicate(conditionpod) && !DoYouHaveLocalPredicate(conditionpod)){
//					System.out.println("JOIN PREDICATE AND NO LOCAL Predicate");
					DBMS.PlanTable.set(5, "S");
					if(DBMS.PlanTable.get(1).equals("R")){
						/**
						 * JOIN PREDICATE AND NO LOCAL PREDICATE
						 * NO INDEX
						 * 
						 * NOT INDEX CASE 
						 * BIGGER TABLE OUTER
						 * */
						int tableone = 0;
						int tabletwo = 0;
//						if(DBMS.orderby == true){
						
						 tableone = Integer.parseInt(DBMS.PlanTable.get(7));
						 tabletwo = Integer.parseInt(DBMS.PlanTable.get(8));
//						}
//						else{
//							tableone = Integer.parseInt(DBMS.PlanTable.get(6));
//							 tabletwo = Integer.parseInt(DBMS.PlanTable.get(7));
//						}
//						System.out.println("tableone " + tableone);
//						System.out.println("tabletwo " + tabletwo);
//						System.out.println("NO LOCAL PLANTABLE " + DBMS.PlanTable);
//						System.out.println("NO LOCAL predi " + cc.prediTable);
						String equation = cc.prediTable.get(0).get(6);
						
						if(tableone < tabletwo){
							/**
							 * need to select right
							 * */
							DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 2));
						}
						else if(tableone > tabletwo)
						{/**
						need to select left
						*/
							
							DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 1));
						}
						else{
							/**
							 * need to slect right
							 * */
							DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 1));
						}
						DBMS.PlanTable.set(5, "S");
					}
					else{
						/**
						 * HAS INDEX
						 * HAS JOIN
						 * HAS NOT LOCAL
						 * 
						 * 1.- if only 1 join column has index, then it should be the inner
						 * 2.the table with the best matching index on join column should be the inner
						 * 3.if both tables have equivalent matching index on join column, larger table should be inner
						 * */
//						System.out.println("H INDEX H JOIN NO LOCAL " + conditionpod );
//						System.out.println("best matching " + MatchCol.bestmatching);
//						System.out.println("tie best matching " + ato.tietea);
						
						if(true == ato.tietea ){
							/**
							 * tie case
							 * smaller outer
							 * */
							int tableone = Integer.parseInt(DBMS.PlanTable.get(7));
							int tabletwo = Integer.parseInt(DBMS.PlanTable.get(8));
							String equation = cc.prediTable.get(0).get(6);
							
							if(tableone < tabletwo){
								DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 1));
//								DBMS.PlanTable.set(7, "T1");
							}
							else if(tableone > tabletwo)
							{
								DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 2));
//								DBMS.PlanTable.set(7,"T2");
							}
							else{
								DBMS.PlanTable.add(ato.GetLeftOrRight(equation, 1));
//								DBMS.PlanTable.set(7,"T1");
							}
							DBMS.PlanTable.set(5, "S");
							
						}
						else{
							/**
							 * not tie: find best matching
							 * */
							// get the T1X1 -> T1
							// need to use getTableName get -> T1.5 , T2.2 -> T1, T2 and compare with T1
//							System.out.println("MatchCol.bestmatching " + MatchCol.bestmatching);
							String name = ato.getTableNameFromIndex(MatchCol.bestmatching);
							ArrayList<String> keies = new ArrayList<String>();
							
							for(int index = 0 ; index < conditionpod.size(); index++){
								if(conditionpod.get(index).trim().startsWith("T")){
									String somename = ato.getTableName(conditionpod.get(index).trim());
									if(!keies.contains(somename.trim())){
										keies.add(somename.trim());
									}
									
								}
							}
							/**
							 * name is the best matching so should be inner so we have find
							 * something is not best matching for outer..
							 * prof i hate uuuu
							 * 
							 * for example name has best matching T1
							 * and we have two table T1, T2
							 * then if T1 != T2 then we know that T2 should be outer
							 * */
							System.out.println("NO JOIN PRDI " + DBMS.PlanTable);
							for(int i = 0 ; i < keies.size() ; i++){
								if(!keies.get(i).trim().equals(name)){
									if( DBMS.PlanTable.size() >9){
									DBMS.PlanTable.set(9,keies.get(i).trim());
									}
									else{
										DBMS.PlanTable.add(keies.get(i).trim());
									}
								}
							}
	
							DBMS.PlanTable.set(5, "S");
							
						}
						/**
						 * check one of them has matching or not
						 * */
						
					}
					
				}

				else{
					/**
					 * case like SELECT T1.1 FROM T1 , T2 WHERE T1.5 = 10
					 * 
					 * */
					System.out.println("THIS IS NOTT JOIN");
				}
				
				
//			}
	 }
	 /**
	  * make sure that there is local predicate in the query
	  * how ? grap "=" then check before and after contain table
	  * 
	  * */
	 
	 public boolean DoYouHaveLocalPredicate(ArrayList<String> conditionpod){
		
		 for(int index  =  0; index < conditionpod.size() ; index++){
			 
			 if(conditionpod.get(index).trim().equals("=") ||
					 (conditionpod.get(index).trim().equals(">") ||
							 (conditionpod.get(index).trim().equals("<"))))
			 {
				 
				 if(!conditionpod.get(index+1).trim().startsWith("T")){
					 return true;
				 }
			 }
			 
		 }
		 
		 
		 return false;
		 
	 }
	 /**
	  * This function is for re-arrange seq when it has
	  * local predicate and join predicate 
	  * 
	  * @param indexOrNot -> 1: has index
	  * 				-> 2: dont use index
	  * 
	  * @return non
	  * 
	  * */
	 public void rearrangeSeq(){
		 /**
		  * get following table
		  * */
		 String followingTable  =  "";
		 if( DBMS.PlanTable.get(9).trim().equals("N") ||  DBMS.PlanTable.get(9).trim().equals("Y")){
			 followingTable = DBMS.PlanTable.get(10);
		 }
		 else{
			 followingTable = DBMS.PlanTable.get(9);
		 }
//		 System.out.println("followingTable " + followingTable);
	
		 ArrayList<String> condidatePredicate  = new ArrayList<String>();
		 ArrayList<String> Neworder =  new ArrayList<String>();
		 for(int index = 0 ; index < cc.prediTable.size() ; index++){
			 condidatePredicate.add(cc.prediTable.get(index).get(6));
		 }
		 
		 /**
		  * get first order with start with following table and not local predicate
		  * */
		 for(int i = 0 ; i < condidatePredicate.size() ; i++){
			 if(condidatePredicate.get(i).startsWith(followingTable) && !ato.isJoinPredicateForString(condidatePredicate.get(i))){
				 Neworder.add(condidatePredicate.get(i));
				 /**
				  * remove un-necessry part
				  * */
				 condidatePredicate.set(i, "99999");
			 }
		 }
		
		
		 
		 for(int ii = 0 ; ii < condidatePredicate.size() ; ii++){
			 if(condidatePredicate.get(ii).startsWith(followingTable)){
				 Neworder.add(condidatePredicate.get(ii));
				 condidatePredicate.set(ii, "99999");
			 }
			 
		 }
	
		 for(int iii = 0 ; iii <condidatePredicate.size() ; iii++){
			 if(!condidatePredicate.get(iii).equals("99999") ){
				 Neworder.add(condidatePredicate.get(iii));	
				 condidatePredicate.set(iii, "99999");
			 }
			
			 
		 }
	
		 
		 for(int iiii = 0 ; iiii < condidatePredicate.size() ; iiii++){
			 String compare = Neworder.get(iiii).trim();
			 for(int inner = 0 ; inner < cc.prediTable.size() ; inner++){				
				 if(compare.equals(cc.prediTable.get(inner).get(6).trim())){
					 cc.prediTable.get(inner).set(5, Integer.toString(iiii+1));
				 }
			 }
			 
		 }
		 
	 }
	 
}
